home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’96
/
O Boy
/
Source
/
AETE_da.cp
< prev
next >
Wrap
Text File
|
1996-06-21
|
20KB
|
746 lines
/*
AETE_da.cp
© Bob Boylan 1996
Revision History
MacHack 1996 initial creation
*/
#include "debug.h"
#include "AETE_da.h"
#include "AEBuild.h"
#include "AppAEObj_pd.h"
#include "ComputerAETE_da.h"
#include "Helpers_ut.h"
#include <sstream>
#include <ASRegistry.h>
#include <UMemoryMgr.h>
#include <algo.h>
// -----------------------------------------------------------------
// GetAstring ... handy for getting data out of the AETE
//
string
GetAstring( istream &ioStream, Boolean inDoAlign );
string
GetAstring( istream &ioStream, Boolean inDoAlign = true )
{
UInt_8 theLen;
char theString[256];
ioStream.read( &theLen,1 );
dassert( theLen >= 0 );
if( theLen > 0 )
{
ioStream.read( (unsigned char *)&theString, theLen );
if( (inDoAlign == true ) &&
((theLen & 0x1) == 0 ) )
{
UInt_8 theAlignByte;
ioStream.read( &theAlignByte,1 );
}
}
else
{ // zero len, but we need to align and the len takes one byte
if( inDoAlign == true )
{
UInt_8 theAlignByte;
ioStream.read( &theAlignByte,1 );
}
}
return string( theString, Int_32(theLen) );
}
// ------------------------------------------------------------
// istream getter of comparison ops
//
istream& operator >> (istream &ioStream, ComparisonOp_da& outComparison)
{
string theName = GetAstring( ioStream );
Int_32 theOPID;
ioStream.read( (unsigned char *)&theOPID, 4 );
string theDesc = GetAstring( ioStream );
return ioStream;
}
// ------------------------------------------------------------
// istream getter of properties
//
istream& operator >> (istream &ioStream, Prop_da& outProp)
{
outProp._Name = GetAstring( ioStream );
ioStream.read( (unsigned char *)&outProp._ID, 4 );
ioStream.read( (unsigned char *)&outProp._Class, 4 );
string theDesc = GetAstring( ioStream );
Int_16 theFlags;
ioStream.read( (unsigned char *)&theFlags, 2 );
return ioStream;
}
// ------------------------------------------------------------
// istream getter of elements (aka submodels)
//
istream& operator >> (istream &ioStream, Elem_da& outElem)
{
ioStream.read( (unsigned char *)&outElem._ID, 4 );
{
Int_16 theFormCount;
ioStream.read( (unsigned char *)&theFormCount, 2 );
for( Int_16 theFormIndex = 1 ; theFormIndex <= theFormCount ; theFormIndex++ )
{
DescType theForm;
ioStream.read( (unsigned char *)&theForm, 4 );
}
}
return ioStream;
}
// ------------------------------------------------------------
// istream getter of enum values
//
istream& operator >> (istream &ioStream, EnumValue_da& outEnumValue)
{
outEnumValue._Name = GetAstring( ioStream );
ioStream.read( (unsigned char *)&outEnumValue._ID, 4 );
string theDesc = GetAstring( ioStream );
return ioStream;
}
// ------------------------------------------------------------
// istream getter of enums
//
istream& operator >> (istream &ioStream, Enum_da& outEnum)
{
ioStream.read( (unsigned char *)&outEnum._ID, 4 );
{
Int_16 theValueCount;
ioStream.read( (unsigned char *)&theValueCount, 2 );
for( Int_16 theValueIndex = 1 ; theValueIndex <= theValueCount ; theValueIndex++ )
{
EnumValue_da theValue;
ioStream >> theValue;
outEnum._Values.push_back( theValue );
}
}
return ioStream;
}
// ------------------------------------------------------------
// istream getter of classes
//
istream& operator >> (istream &ioStream, Class_da& outClass)
{
outClass._Name = GetAstring( ioStream );
ioStream.read( (unsigned char *)&outClass._ID, 4 );
string theDesc = GetAstring( ioStream );
{ // the properties
Int_16 thePropCount;
ioStream.read( (unsigned char *)&thePropCount, 2 );
for( Int_16 thePropIndex = 1 ; thePropIndex <= thePropCount ; thePropIndex++ )
{
Prop_da theProp;
ioStream >> theProp;
outClass._Props.push_back( theProp );
}
}
{ // the elements (sub models)
Int_16 theEleCount;
ioStream.read( (unsigned char *)&theEleCount, 2 );
for( Int_16 theEleIndex = 1 ; theEleIndex <= theEleCount ; theEleIndex++ )
{
Elem_da theElem;
ioStream >> theElem;
outClass._Elems.push_back( theElem );
}
}
return ioStream;
}
// ------------------------------------------------------------
// istream getter of event parameters
//
istream& operator >> (istream &ioStream, EventParam_da& outEventParam)
{
outEventParam._Name = GetAstring( ioStream );
DescType theKeyWord;
ioStream.read( (unsigned char *)&theKeyWord, 4 );
DescType theType;
ioStream.read( (unsigned char *)&theType, 4 );
string theParamDesc = GetAstring( ioStream );
Int_16 theParamFlags;
ioStream.read( (unsigned char *)&theParamFlags, 2 );
return ioStream;
}
// ------------------------------------------------------------
// istream getter of events
//
istream& operator >> (istream &ioStream, Event_da& outEvent)
{
outEvent._Name = GetAstring( ioStream, false );
string theEventDesc = GetAstring( ioStream, false );
if( ((outEvent._Name.length() + theEventDesc.length() ) & 1 ) == 1 )
{
UInt_8 theAlignByte;
ioStream.read( &theAlignByte,1 );
}
DescType theEventClass;
ioStream.read( (unsigned char *)&theEventClass, 4 );
DescType theEventID;
ioStream.read( (unsigned char *)&theEventID, 4 );
DescType theReplyParam;
ioStream.read( (unsigned char *)&theReplyParam, 4 );
string theReplyDesc = GetAstring( ioStream );
Int_16 theReplyFlags;
ioStream.read( (unsigned char *)&theReplyFlags, 2 );
DescType theParamType;
ioStream.read( (unsigned char *)&theParamType, 4 );
string theParamDesc = GetAstring( ioStream );
Int_16 thePFlags;
ioStream.read( (unsigned char *)&thePFlags, 2 );
{
Int_16 theAdditionalParamCount;
ioStream.read( (unsigned char *)&theAdditionalParamCount, 2 );
for( Int_16 theEParamIndex = 1 ; theEParamIndex <= theAdditionalParamCount ; theEParamIndex++ )
{
EventParam_da theEventParam;
ioStream >> theEventParam;
outEvent._Params.push_back( theEventParam );
}
}
return ioStream;
}
// ------------------------------------------------------------
// istream getter of suites
//
istream& operator >> (istream &ioStream, Suite_da& outSuite)
{
outSuite._Name = GetAstring( ioStream, false );
string theSuiteDescription = GetAstring( ioStream, false );
if( ((outSuite._Name.length() + theSuiteDescription.length() ) & 1 ) == 1 )
{
UInt_8 theAlignByte;
ioStream.read( &theAlignByte,1 );
}
{
Int_32 theSuiteID;
ioStream.read( (unsigned char *)&theSuiteID, 4 );
Int_16 theSuiteLevel;
ioStream.read( (unsigned char *)&theSuiteLevel, 2 );
Int_16 theSuiteVersion;
ioStream.read( (unsigned char *)&theSuiteVersion, 2 );
{ // events
Int_16 theEventCount;
ioStream.read( (unsigned char *)&theEventCount, 2 );
for( Int_16 theEventIndex = 1 ; theEventIndex <= theEventCount ; theEventIndex++ )
{
Event_da theEvent;
ioStream >> theEvent;
outSuite._Events.push_back( theEvent );
}
}
{ // classes
Int_16 theClassCount;
ioStream.read( (unsigned char *)&theClassCount, 2 );
for( Int_16 theClassIndex = 1 ; theClassIndex <= theClassCount ; theClassIndex++ )
{
Class_da theClass;
ioStream >> theClass;
outSuite._Classes.push_back( theClass );
}
}
{ // comparison operators
Int_16 theComparisonCount;
ioStream.read( (unsigned char *)&theComparisonCount, 2 );
for( Int_16 theCompIndex = 1 ; theCompIndex <= theComparisonCount ; theCompIndex++ )
{
ComparisonOp_da theComp;
ioStream >> theComp;
outSuite._CompOps.push_back( theComp);
}
}
{ // enumerations
Int_16 theEnumCount;
ioStream.read( (unsigned char *)&theEnumCount, 2 );
for( Int_16 theEnumIndex = 1 ; theEnumIndex <= theEnumCount ; theEnumIndex++ )
{
Enum_da theEnum;
ioStream >> theEnum;
outSuite._Enums.push_back( theEnum );
}
}
}
return ioStream;
}
// -----------------------------------------------------------------
// AnyEnum_2_typeChar_Ptr - ae coercion handler from any enum to char
// ... will find the char string associated with an enum
//
pascal
OSErr
AnyEnum_2_typeChar_Ptr( DescType inTypeCode, const void * indataPtr, Size indataSize, DescType intoType, Int_32 inhandlerRefcon, AEDesc *outresult );
pascal
OSErr
AnyEnum_2_typeChar_Ptr( DescType inTypeCode, const void * indataPtr, Size indataSize, DescType intoType, Int_32 inhandlerRefcon, AEDesc *outresult )
{
Int_32 theEnumValue = (*((Int_32 *) indataPtr));
AETE_da * theAETEP = (AETE_da *) inhandlerRefcon; // refcon holds the aete object *
dassert( theAETEP != nil );
string theEnumName = theAETEP->GetEnumName( theEnumValue );
OSErr theRetVal = ::AECreateDesc(intoType, (Ptr) theEnumName.c_str(), theEnumName.length(), outresult );
return theRetVal;
}
// -----------------------------------------------------------------
// Boolean_2_typeChar_Ptr - ae coercion handler from boolean to char
//
pascal
OSErr
Boolean_2_typeChar_Ptr( DescType inTypeCode, const void * indataPtr, Size indataSize, DescType intoType, Int_32 inhandlerRefcon, AEDesc *outresult );
pascal
OSErr
Boolean_2_typeChar_Ptr( DescType inTypeCode, const void * indataPtr, Size indataSize, DescType intoType, Int_32 inhandlerRefcon, AEDesc *outresult )
{
#pragma unused( inhandlerRefcon )
Boolean theValue = (*((Boolean *) indataPtr));
string theValueAsString;
if( theValue )
{
theValueAsString = string("True");
}
else
{
theValueAsString = string("False");
}
OSErr theRetVal = ::AECreateDesc(intoType, (Ptr) theValueAsString.c_str(), theValueAsString.length(), outresult );
return theRetVal;
}
// ---------------------------------------------------------------------------------- AETE
// -----------------------------------------------------------------
// ctor
//
AETE_da::AETE_da()
: _EnumHandlerUPP( nil ),
_BooleanHandlerUPP( nil )
{}
// -----------------------------------------------------------------
// ctor (with application object)
//
AETE_da::AETE_da( AppAEObj_pd *inApp )
: _EnumHandlerUPP( nil ),
_BooleanHandlerUPP( nil )
{
Clone_ut<StAEDescriptor> theAETE = RetrieveFromApp( inApp );
if( (*theAETE).mDesc.descriptorType == typeNull )
{
// not really scriptable
}
else
{ // ok, we now have the data, need to make sense of it ...
// we can get either a list or a single aete
if( (*theAETE).mDesc.descriptorType == typeAEList )
{
Int_32 theNItems;
// a list of aetes
::AECountItems( &(*theAETE).mDesc, &theNItems );
for( Int_32 theIndex=1; theIndex<=theNItems; theIndex++ )
{
{
StAEDescriptor theAETEItem;
DescType theType;
OSErr anErr = AEGetNthDesc( &(*theAETE).mDesc, theIndex,
typeWildCard, &theType, &theAETEItem.mDesc );
StHandleLocker theLock( theAETEItem.mDesc.dataHandle );
IncorpAETE( theAETEItem.mDesc.dataHandle );
}
}
}
else
{
StHandleLocker theLock( (*theAETE).mDesc.dataHandle );
IncorpAETE( (*theAETE).mDesc.dataHandle );
}
{ // install the coercion handler
_EnumHandlerUPP = NewAECoercePtrProc( AnyEnum_2_typeChar_Ptr );
_BooleanHandlerUPP = NewAECoercePtrProc( Boolean_2_typeChar_Ptr );
// install it
#if GENERATINGPOWERPC
OSErr theErr = AEInstallCoercionHandler( typeEnumerated, typeChar, _EnumHandlerUPP, (Int_32)this, false, false );
theErr = AEInstallCoercionHandler( typeBoolean, typeChar, _BooleanHandlerUPP, (Int_32)this, false, false );
#else
OSErr theErr = AEInstallCoercionHandler( typeEnumerated, typeChar, (ProcPtr)_EnumHandlerUPP, (Int_32)this, false, false );
theErr = AEInstallCoercionHandler( typeBoolean, typeChar, (ProcPtr)_BooleanHandlerUPP, (Int_32)this, false, false );
#endif
}
}
// for optimization we have this 'last class' bookmark
ClassIterator_ut theNullSet;
_LastClass = theNullSet;
}
// -----------------------------------------------------------------
// dtor
//
AETE_da::~AETE_da()
{
// clean up the ae coercion handlers
if( _EnumHandlerUPP != nil )
{
#if GENERATINGPOWERPC
AERemoveCoercionHandler( typeEnumerated, typeChar, _EnumHandlerUPP, false );
AERemoveCoercionHandler( typeBoolean, typeChar, _BooleanHandlerUPP, false );
#else
AERemoveCoercionHandler( typeEnumerated, typeChar, (ProcPtr)_EnumHandlerUPP, false );
AERemoveCoercionHandler( typeBoolean, typeChar, (ProcPtr)_BooleanHandlerUPP, false );
#endif
DisposeRoutineDescriptor( _EnumHandlerUPP );
DisposeRoutineDescriptor( _BooleanHandlerUPP );
_EnumHandlerUPP = nil;
_BooleanHandlerUPP = nil;
}
}
// -----------------------------------------------------------------
// GetProperties ... associated with a given class
//
vector<Prop_da>
AETE_da::GetProperties( const DescType inClassID )
{
vector<Prop_da> theRetVal;
// quick exit check
if( (*_LastClass)._ID == inClassID )
{
theRetVal = (*_LastClass)._Props;
}
else
{ // search the list we have already parsed
ClassIterator_ut theFirstClass( &_Suites );
ClassIterator_ut theLastClass ( &_Suites,true );
Class_da theClassWeWant;
theClassWeWant._ID = inClassID;
ClassIterator_ut theFoundItem = find( theFirstClass, theLastClass, theClassWeWant );
if( theFoundItem != theLastClass )
{
_LastClass = theFoundItem;
theRetVal = (*_LastClass)._Props;
}
}
return theRetVal;
}
// -----------------------------------------------------------------
// GetElements ... associated with a given class
//
vector<Elem_da>
AETE_da::GetElements( const DescType inClassID )
{
vector<Elem_da> theRetVal;
// quick exit check
if( (*_LastClass)._ID == inClassID )
{
theRetVal = (*_LastClass)._Elems;
}
else
{
ClassIterator_ut theFirstClass( &_Suites );
ClassIterator_ut theLastClass ( &_Suites,true );
if( inClassID != cFinderProcess)
{ // with an object we look in it's element list
Class_da theClassWeWant;
theClassWeWant._ID = inClassID;
ClassIterator_ut theFoundItem = find( theFirstClass, theLastClass, theClassWeWant );
if( theFoundItem != theLastClass )
{
_LastClass = theFoundItem;
theRetVal = (*_LastClass)._Elems;
}
}
else
{ // with an 'application' we hand back all the class types
while( theFirstClass != theLastClass )
{
Elem_da theElem;
theElem._ID = (*theFirstClass)._ID;
theRetVal.push_back( theElem );
++theFirstClass;
}
}
}
return theRetVal;
}
// -----------------------------------------------------------------
// GetEnumName ... search all enums for a given value
//
string
AETE_da::GetEnumName( const DescType inEnumValue )
{
string theRetVal;
EnumValue_da theValueWeWant;
theValueWeWant._ID = inEnumValue;
pair< vector<EnumValue_da>::iterator,vector<EnumValue_da>::iterator> theFoundItem
= equal_range( _EnumMap.begin(), _EnumMap.end(), theValueWeWant );
if( theFoundItem.first != _EnumMap.end() )
{
theRetVal = (*(theFoundItem.first))._Name;
}
else
{
theRetVal = As4CharString( inEnumValue );
}
return theRetVal;
}
// -----------------------------------------------------------------
// GetClassName
//
string
AETE_da::GetClassName( const DescType inClassID )
{
string theRetVal;
ClassIterator_ut theFirstClass( &_Suites );
ClassIterator_ut theLastClass ( &_Suites,true );
Class_da theClassWeWant;
theClassWeWant._ID = inClassID;
ClassIterator_ut theFoundItem = find( theFirstClass, theLastClass, theClassWeWant );
if( theFoundItem != theLastClass )
{
theRetVal = (*theFoundItem)._Name;
}
else
{ // hmmm ... the class wasn't there? must be an application
if( inClassID == cFinderProcess )
{
theRetVal = string("App");
}
else
{ // if not, maybe the user can make some sense of it
theRetVal = As4CharString( inClassID );
}
}
return theRetVal;
}
// -----------------------------------------------------------------
// RetrieveFromApp ... get the 'aete' data from the application
//
Clone_ut<StAEDescriptor>
AETE_da::RetrieveFromApp( AppAEObj_pd *inApp )
{
ostringstream theStream( ios::in | ios::out );
theStream << "'----': 0"; // the lang code
OSErr theErr;
StAEDescriptor theAppleEvent;
// use gizmos to create the apple event
theErr = AEBuildAppleEvent( kASAppleScriptSuite, kGetAETE,
inApp->GetAppAddrType(),
inApp->GetAppAddr(),
inApp->GetSizeofAppAddr(),
kAutoGenerateReturnID, kAnyTransactionID,
&theAppleEvent.mDesc, theStream.str().c_str() );
dassert( theErr == noErr );
StAEDescriptor theReplyAppleEvent;
// and off with it
theErr = AESend( &theAppleEvent.mDesc, &theReplyAppleEvent.mDesc, kAEWaitReply,
kAENormalPriority, 61, nil, nil ); // timeout = 61
// package up the return value
StAEDescriptor *theResult = new StAEDescriptor;
Clone_ut<StAEDescriptor> theRetVal( theResult );
if( theErr == noErr )
{
theErr = AEGetParamDesc( theReplyAppleEvent, keyDirectObject, typeWildCard, &theResult->mDesc );
}
return theRetVal;
}
// -----------------------------------------------------------------
// IncorpAETE ... merge with existing data
//
void
AETE_da::IncorpAETE( Handle inAETEHandle )
{
StHandleLocker theLock( inAETEHandle );
istringstream theStream( string((char *) *inAETEHandle, GetHandleSize(inAETEHandle) ), ios::in | ios::binary);
{
// read the up front stuff
char theDummy[2];
theStream.read( theDummy, 2 ); // aete version
theStream.read( theDummy, 2 ) ; // lang
theStream.read( theDummy, 2 ) ; // script
Int_16 theSuiteCount;
theStream.read( (char *) &theSuiteCount, 2 );
for( Int_16 theIndex = 1 ; theIndex <= theSuiteCount ; theIndex ++ )
{
Suite_da theNewSuite;
theStream >> theNewSuite;
_Suites.push_back( theNewSuite );
{ // update the enum map ... needed for quick access to the enum names
vector<Enum_da>::iterator theEIter = theNewSuite._Enums.begin();
while( theEIter != theNewSuite._Enums.end() )
{
vector<EnumValue_da>::iterator theEVIter = (*theEIter)._Values.begin();
while( theEVIter != (*theEIter)._Values.end() )
{
_EnumMap.push_back( *theEVIter );
++theEVIter;
}
++theEIter;
}
}
}
sort( _EnumMap.begin(), _EnumMap.end() ); // for later binary search
}
}
// ---------------------------------------------------------------------------------------------
// -----------------------------------------------------------------
// ClassIterator_ut ctor
//
AETE_da::ClassIterator_ut::ClassIterator_ut( vector<Suite_da> * inSuites, Boolean inPointToEnd )
: _SuitesP( inSuites ),
_SuiteIndex( 0 ),
_ClassIndex( 0 )
{
dassert( inSuites != nil );
if( inPointToEnd == true )
{
_SuiteIndex = _SuitesP->size();
}
else
{ // could be the first suite doesn't have any classes
while( (_SuiteIndex < _SuitesP->size() ) &&
((*_SuitesP)[_SuiteIndex]._Classes.size() == 0 ))
{
++_SuiteIndex;
}
}
}
// -----------------------------------------------------------------
// != operator
//
Boolean
AETE_da::ClassIterator_ut::operator !=( const ClassIterator_ut & inOther )
{
if( (_SuiteIndex == inOther._SuiteIndex) &&
(_ClassIndex == inOther._ClassIndex) )
return false;
else
return true;
}
// -----------------------------------------------------------------
// ++ operator
//
AETE_da::ClassIterator_ut
AETE_da::ClassIterator_ut::operator ++()
{
dassert( _SuiteIndex < _SuitesP->size() );
dassert( _ClassIndex <= (*_SuitesP)[_SuiteIndex]._Classes.size() );
if( (_ClassIndex + 1) < (*_SuitesP)[_SuiteIndex]._Classes.size() )
{
++_ClassIndex;
}
else
{
// see if this suite has any classes, if not then move on to the next one
++_SuiteIndex;
while( (_SuiteIndex < _SuitesP->size() ) &&
((*_SuitesP)[_SuiteIndex]._Classes.size() == 0 ))
{
++_SuiteIndex;
}
_ClassIndex = 0;
}
return *this;
}
// -----------------------------------------------------------------
// * operator
//
Class_da &
AETE_da::ClassIterator_ut::operator *()
{
if( _SuitesP == nil )
{
Class_da theRetVal;
theRetVal._ID = typeNull;
return theRetVal;
}
else
{
return (*_SuitesP)[_SuiteIndex]._Classes[_ClassIndex];
}
}